package paginacao;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import br.com.sgc.enuns.TipoOrdenacao;
import br.com.sgc.session.GenericSession;

public class ListaPaginada<T> extends AbstractList<T> implements Serializable{

	private static final long serialVersionUID = 3774125359078513613L;

	/** cache of loaded items. */
	private Map<Integer, T> loaded;

	/** total number of results expected. */
	private Long numResults;

	/** number of results to fetch on cache miss. */
	private int pageSize;

	private GenericSession<T> service;

	private T modelClass;

	private String orderField;	
	
	private Long clinicaId;
	
	private TipoOrdenacao tipoOrdenacao;
	
	public ListaPaginada(GenericSession<T> service, Long clinicaId, T modelClass, String orderField) {
		this(service, clinicaId, modelClass, 10, orderField);
	}
	
	public ListaPaginada(GenericSession<T> service, Long clinicaId, T modelClass, int pageSize, String orderField) {
		loaded = new HashMap<Integer, T>(pageSize);
		this.pageSize = pageSize;
		this.service = service;
		this.modelClass = modelClass;
		this.orderField = orderField;
		this.clinicaId = clinicaId;
	}
	
	public ListaPaginada(GenericSession<T> service, Long clinicaId, T modelClass, int pageSize, String orderField, TipoOrdenacao tipoOrdenacao) {
		loaded = new HashMap<Integer, T>(pageSize);
		this.pageSize = pageSize;
		this.service = service;
		this.modelClass = modelClass;
		this.orderField = orderField;
		this.tipoOrdenacao = tipoOrdenacao;
		this.clinicaId = clinicaId;
	}
	
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * Fetch an item, loading it from the query results if it hasn't already
	 * been. {@inheritDoc}
	 */
	@Override
	public T get(int i) {
		if (!loaded.containsKey(i)) {
			loaded.clear();
			final List<T> results = consultarRegistros(i, pageSize);
			for (int j = 0; j < results.size(); j++) {
				loaded.put(i + j, results.get(j));
			}
		}
		return loaded.get(i);
	}

	/** {@inheritDoc} */
	@Override
	public int size() {
		if (this.numResults == null) { 
            this.numResults = count(); 
        } 
        return numResults.intValue(); 
	}

	/**
	 * Contar a quantidade total de registros.
	 * 
	 * @return quantidade encontrada
	 */
	protected long count(){
		return service.count(modelClass, clinicaId);
	}

	/**
	 * Consultar a pageSize registros apartir da posicao inicial.
	 * 
	 * @param posicaoInicial
	 *            posicao inicial
	 * @param pageSize
	 *            tamanho da pagina
	 * @return os registros consultados
	 */
	protected List<T> consultarRegistros(int posicaoInicial,int pageSize) {
		if(tipoOrdenacao != null){
			return service.findAll(modelClass, clinicaId, posicaoInicial, pageSize, orderField, true, tipoOrdenacao);
		}
		
		return service.findAll(modelClass, clinicaId, posicaoInicial, pageSize, orderField, true);
	}
}
